/*
 * @Author: jingfuu@163.com
 * @Date: 2024-09-20 09:49:26
 * @LastEditTime: 2024-12-03 15:09:26
 * @Description: 授权守卫
 */

import {
  CanActivate,
  ExecutionContext,
  Injectable,
  UnauthorizedException,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Constants } from '../Constants';
import { ClsService } from 'nestjs-cls';
import { CacheKey } from '../CacheKey';
import * as micromatch from 'micromatch';
import { CacheUtil } from '../CacheUtil';
import { ConfigService } from '@nestjs/config';
import SystemConfigService from 'src/system/service/SystemConfigService';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(
    private jwtService: JwtService,
    private cls: ClsService,
    private configService: ConfigService,
    private systemConfigService: SystemConfigService,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest();
    const url = request.originalUrl;
    //白名单放行
    const whitelist = this.configService.get('WHITE_URL').split(',');
    const isMatched = micromatch.isMatch(url, whitelist);
    if (isMatched) return true;
    const token = this.cls.get(Constants.USER_TOKEN);
    if (!token) {
      throw new UnauthorizedException();
    }
    try {
      const payload = await this.jwtService.verifyAsync(token, {
        secret: Constants.JWT_SECRET,
      });
      //校验登录是否过期
      const userId = await CacheUtil.getCacheObject(
        CacheKey.USER_TOKEN + token,
      );
      if (!userId) {
        throw new UnauthorizedException();
      } else {
        // 每次访问只要token没失效就设为7天有效
        CacheUtil.setCacheObject(
          CacheKey.USER_TOKEN + token,
          payload.sub,
          3600 * (await this.systemConfigService.getUserSessionEffectiveTime()),
        );
      }
      //获取redis登录用户session放入cls中
      this.cls.set(
        Constants.USER_SESSION,
        await CacheUtil.getCacheObject(CacheKey.USER_SESSION + userId),
      );
    } catch {
      throw new UnauthorizedException();
    }
    return true;
  }
}
